/*
 * Unidata Platform
 * Copyright (c) 2013-2020, UNIDATA LLC, All rights reserved.
 *
 * Commercial License
 * This version of Unidata Platform is licensed commercially and is the appropriate option for the vast majority of use cases.
 *
 * Please see the Unidata Licensing page at: https://unidata-platform.com/license/
 * For clarification or additional options, please contact: info@unidata-platform.com
 * -------
 * Disclaimer:
 * -------
 * THIS SOFTWARE IS DISTRIBUTED "AS-IS" WITHOUT ANY WARRANTIES, CONDITIONS AND
 * REPRESENTATIONS WHETHER EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION THE
 * IMPLIED WARRANTIES AND CONDITIONS OF MERCHANTABILITY, MERCHANTABLE QUALITY,
 * FITNESS FOR A PARTICULAR PURPOSE, DURABILITY, NON-INFRINGEMENT, PERFORMANCE AND
 * THOSE ARISING BY STATUTE OR FROM CUSTOM OR USAGE OF TRADE OR COURSE OF DEALING.
 */
package org.unidata.mdm.rest.v1.meta.configuration;

import java.util.Arrays;
import java.util.Collections;
import javax.ws.rs.core.Application;
import javax.ws.rs.ext.RuntimeDelegate;

import com.fasterxml.jackson.jaxrs.json.JacksonJaxbJsonProvider;
import org.apache.cxf.Bus;
import org.apache.cxf.endpoint.Server;
import org.apache.cxf.jaxrs.JAXRSServerFactoryBean;
import org.apache.cxf.jaxrs.openapi.OpenApiFeature;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.unidata.mdm.rest.system.exception.DetailedRestExceptionMapper;
import org.unidata.mdm.rest.system.service.ReceiveInInterceptor;
import org.unidata.mdm.rest.system.util.OpenApiMetadataFactory;
import org.unidata.mdm.rest.v1.meta.service.MetaRestApplication;
import org.unidata.mdm.rest.v1.meta.service.entities.LookupEntityRestService;
import org.unidata.mdm.rest.v1.meta.service.entities.NestedEntityRestService;
import org.unidata.mdm.rest.v1.meta.service.entities.RegisterEntityRestService;
import org.unidata.mdm.rest.v1.meta.service.enumeration.EnumerationRestService;
import org.unidata.mdm.rest.v1.meta.service.groups.EntitiesGroupRestService;
import org.unidata.mdm.rest.v1.meta.service.measurement.MeasurementUnitsRestService;
import org.unidata.mdm.rest.v1.meta.service.model.MetaInputOutputRestService;
import org.unidata.mdm.rest.v1.meta.service.model.MetaModelRestService;
import org.unidata.mdm.rest.v1.meta.service.relations.RelationRestService;
import org.unidata.mdm.rest.v1.meta.service.search.MetaSearchRestService;
import org.unidata.mdm.rest.v1.meta.service.systems.SourceSystemRestService;

/**
 * @author Alexander Malyshev
 */
@Configuration
public class MetaRestConfiguration {

    @Bean
    public Application metaRestApplication() {
        return new MetaRestApplication();
    }

    @Bean
    public EntitiesGroupRestService entitiesGroupRestService() {
        return new EntitiesGroupRestService();
    }

    @Bean
    public RegisterEntityRestService entityRestService() {
        return new RegisterEntityRestService();
    }

    @Bean
    public EnumerationRestService enumerationRestService() {
        return new EnumerationRestService();
    }

    @Bean
    public LookupEntityRestService lookupEntityRestService() {
        return new LookupEntityRestService();
    }

    @Bean
    public MeasurementUnitsRestService measurementUnitsRestService() {
        return new MeasurementUnitsRestService();
    }

    @Bean
    public MetaModelRestService metaModelRestService() {
        return new MetaModelRestService();
    }

    @Bean
    public RelationRestService relationRestService() {
        return new RelationRestService();
    }

    @Bean
    public NestedEntityRestService nestedRestService() {
        return new NestedEntityRestService();
    }

    @Bean
    public SourceSystemRestService sourceSystemRestService() {
        return new SourceSystemRestService();
    }

    @Bean
    public MetaSearchRestService metaSearchRestService() {
        return new MetaSearchRestService();
    }

    @Bean
    public MetaInputOutputRestService metaInputOutputRestService() {
        return new MetaInputOutputRestService();
    }

    @Bean
    public DetailedRestExceptionMapper detailedRestExceptionMapper() {
        return new DetailedRestExceptionMapper(() -> "META_REST_SERVICE");
    }

    @Bean
    public Server server(
            final Bus cxf,
            final Application metaRestApplication,
            final JacksonJaxbJsonProvider jacksonJaxbJsonProvider,
            final DetailedRestExceptionMapper restExceptionMapper,
            final ReceiveInInterceptor receiveInInterceptor,
            final EntitiesGroupRestService entitiesGroupRestService,
            final RegisterEntityRestService entityRestService,
            final EnumerationRestService enumerationRestService,
            final LookupEntityRestService lookupEntityRestService,
            final MeasurementUnitsRestService measurementUnitsRestService,
            final MetaModelRestService metaModelRestService,
            final RelationRestService relationRestService,
            final SourceSystemRestService sourceSystemRestService,
            final MetaSearchRestService metaSearchRestService,
            final MetaInputOutputRestService metaInputOutputRestService,
            final NestedEntityRestService nestedRestService
    ) {
        final JAXRSServerFactoryBean jaxrsServerFactoryBean = RuntimeDelegate.getInstance()
                .createEndpoint(metaRestApplication, JAXRSServerFactoryBean.class);

        final OpenApiFeature metaOpenApiFeature = OpenApiMetadataFactory.openApiFeature(
                "Unidata meta API",
                "Unidata meta REST API operations",
                metaRestApplication, cxf,
                "org.unidata.mdm.rest.v1.meta.service");

        jaxrsServerFactoryBean.setFeatures(Collections.singletonList(metaOpenApiFeature));
        jaxrsServerFactoryBean.setProviders(Arrays.asList(jacksonJaxbJsonProvider, restExceptionMapper));
        jaxrsServerFactoryBean.setInInterceptors(Collections.singletonList(receiveInInterceptor));
        jaxrsServerFactoryBean.setServiceBeans(
                Arrays.asList(
                        entitiesGroupRestService,
                        entityRestService,
                        enumerationRestService,
                        lookupEntityRestService,
                        measurementUnitsRestService,
                        metaModelRestService,
                        relationRestService,
                        sourceSystemRestService,
                        metaSearchRestService,
                        metaInputOutputRestService,
                        nestedRestService
                )
        );

        return jaxrsServerFactoryBean.create();
    }
}
